Popular Searches
Popular Course Categories
Popular Courses

Creating text input fields

Creating text input fields

Flutter Forms & User Input


Creating Text Input Fields in Flutter


Text input fields are an essential part of Flutter applications because they allow users to enter information such as names, email addresses, passwords, phone numbers, search terms, comments, and messages. Flutter provides the TextField widget for general text input and TextFormField when the input needs to work with a Form and validation. :contentReference[oaicite:0]{index=0}




1. What Is a Text Input Field?


A text input field is a user-interface component where users can type or edit text. In Flutter, the most common widget for creating a text input field is TextField.


Text input fields are commonly used for:



  • Username input

  • Name and address forms

  • Email addresses

  • Phone numbers

  • Passwords

  • Search boxes

  • Chat messages

  • Comments and feedback

  • Product search

  • Registration and login forms




2. Basic TextField Syntax


TextField(
  decoration: InputDecoration(
    labelText: 'Enter your name',
  ),
)

The TextField accepts keyboard input and can be customized using properties such as controller, keyboardType, obscureText, maxLines, onChanged, and onSubmitted. :contentReference[oaicite:1]{index=1}




3. Complete Basic Example


import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Text Input Example'),
        ),
        body: const Padding(
          padding: EdgeInsets.all(20),
          child: TextField(
            decoration: InputDecoration(
              labelText: 'Name',
              hintText: 'Enter your name',
              border: OutlineInputBorder(),
            ),
          ),
        ),
      ),
    );
  }
}




4. Understanding InputDecoration


InputDecoration controls the visual appearance of a Material text input field. It can provide labels, hints, icons, helper text, error text, borders, prefixes, suffixes, and other styling options. :contentReference[oaicite:2]{index=2}


Common Properties

















PropertyPurpose
labelTextDisplays a label for the input.
hintTextDisplays an example or instruction.
helperTextDisplays additional information below the field.
errorTextDisplays an error message.
prefixIconDisplays an icon before the input.
suffixIconDisplays an icon after the input.
prefixTextDisplays text before the entered value.
suffixTextDisplays text after the entered value.
borderDefines the default border.
focusedBorderDefines the border when the field is focused.
enabledBorderDefines the border when the field is enabled but not focused.
filledDetermines whether the background is filled.
fillColorDefines the background color.



5. Creating a TextField with a Label


TextField(
  decoration: InputDecoration(
    labelText: 'Full Name',
    border: OutlineInputBorder(),
  ),
)

The label identifies what information the user should enter.




6. Creating a TextField with Hint Text


TextField(
  decoration: InputDecoration(
    hintText: 'Enter your full name',
    border: OutlineInputBorder(),
  ),
)

The hint provides an example or instruction inside the input area.




7. Label and Hint Together


TextField(
  decoration: InputDecoration(
    labelText: 'Email Address',
    hintText: '[email protected]',
    border: OutlineInputBorder(),
  ),
)



8. Adding Icons to Text Input Fields


Prefix Icon


TextField(
  decoration: InputDecoration(
    labelText: 'Username',
    prefixIcon: Icon(Icons.person),
    border: OutlineInputBorder(),
  ),
)

Suffix Icon


TextField(
  decoration: InputDecoration(
    labelText: 'Search',
    suffixIcon: Icon(Icons.search),
    border: OutlineInputBorder(),
  ),
)

Prefix and Suffix Together


TextField(
  decoration: InputDecoration(
    labelText: 'Email',
    prefixIcon: Icon(Icons.email),
    suffixIcon: Icon(Icons.check),
    border: OutlineInputBorder(),
  ),
)



9. Different Border Styles


Outline Border


TextField(
  decoration: InputDecoration(
    labelText: 'Name',
    border: OutlineInputBorder(),
  ),
)

Rounded Outline Border


TextField(
  decoration: InputDecoration(
    labelText: 'Name',
    border: OutlineInputBorder(
      borderRadius: BorderRadius.circular(12),
    ),
  ),
)

Underline Border


TextField(
  decoration: InputDecoration(
    labelText: 'Name',
    border: UnderlineInputBorder(),
  ),
)



10. Filled Text Input Field


TextField(
  decoration: InputDecoration(
    labelText: 'Username',
    filled: true,
    fillColor: Colors.grey,
    border: OutlineInputBorder(
      borderRadius: BorderRadius.circular(10),
    ),
  ),
)



11. TextEditingController


TextEditingController allows the application to read and control the text entered into a TextField. It can also be used to set an initial value and observe changes. When a controller is created by a StatefulWidget, it should be disposed when it is no longer needed. :contentReference[oaicite:3]{index=3}


class NamePage extends StatefulWidget {
  const NamePage({super.key});

  @override
  State createState() => _NamePageState();
}

class _NamePageState extends State {
  final nameController = TextEditingController();

  @override
  void dispose() {
    nameController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Padding(
        padding: const EdgeInsets.all(20),
        child: TextField(
          controller: nameController,
          decoration: const InputDecoration(
            labelText: 'Name',
            border: OutlineInputBorder(),
          ),
        ),
      ),
    );
  }
}




12. Retrieving Input from TextField


Use the controller's text property to retrieve the current value.


String name = nameController.text;

Example


ElevatedButton(
  onPressed: () {
    print(nameController.text);
  },
  child: const Text('Get Name'),
)



13. Setting Initial Text


final nameController = TextEditingController(
  text: 'John Doe',
);

Then connect it to the TextField:


TextField(
  controller: nameController,
)



14. Detecting Text Changes with onChanged


The onChanged callback runs whenever the user changes the text. It is useful for live search, character counters, filtering, and dynamic UI updates. :contentReference[oaicite:4]{index=4}


TextField(
  onChanged: (value) {
    print('Entered text: $value');
  },
  decoration: InputDecoration(
    labelText: 'Search',
    border: OutlineInputBorder(),
  ),
)

Live Character Counter


class CharacterCounter extends StatefulWidget {
  const CharacterCounter({super.key});

  @override
  State createState() => _CharacterCounterState();
}

class _CharacterCounterState extends State {
  int count = 0;

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        TextField(
          onChanged: (value) {
            setState(() {
              count = value.length;
            });
          },
          decoration: const InputDecoration(
            labelText: 'Message',
            border: OutlineInputBorder(),
          ),
        ),
        const SizedBox(height: 10),
        Text('Characters: $count'),
      ],
    );
  }
}




15. Handling Submitted Text


The onSubmitted callback runs when the user submits the field, commonly by using the action button on the keyboard. :contentReference[oaicite:5]{index=5}


TextField(
  onSubmitted: (value) {
    print('Submitted: $value');
  },
  decoration: const InputDecoration(
    labelText: 'Search',
    border: OutlineInputBorder(),
  ),
)



16. Creating an Email Input Field


For email input, use TextInputType.emailAddress so the platform can provide an appropriate keyboard layout.


TextField(
  keyboardType: TextInputType.emailAddress,
  decoration: const InputDecoration(
    labelText: 'Email Address',
    hintText: '[email protected]',
    prefixIcon: Icon(Icons.email),
    border: OutlineInputBorder(),
  ),
)



17. Creating a Phone Number Input Field


TextField(
  keyboardType: TextInputType.phone,
  decoration: const InputDecoration(
    labelText: 'Phone Number',
    prefixIcon: Icon(Icons.phone),
    border: OutlineInputBorder(),
  ),
)



18. Creating a Number Input Field


TextField(
  keyboardType: TextInputType.number,
  decoration: const InputDecoration(
    labelText: 'Age',
    prefixIcon: Icon(Icons.numbers),
    border: OutlineInputBorder(),
  ),
)



19. Creating a Password Input Field


Use obscureText: true when the entered characters should be hidden, such as in a password field. :contentReference[oaicite:6]{index=6}


TextField(
  obscureText: true,
  decoration: const InputDecoration(
    labelText: 'Password',
    prefixIcon: Icon(Icons.lock),
    border: OutlineInputBorder(),
  ),
)



20. Password Visibility Toggle


class PasswordField extends StatefulWidget {
  const PasswordField({super.key});

  @override
  State createState() => _PasswordFieldState();
}

class _PasswordFieldState extends State {
  bool obscurePassword = true;

  @override
  Widget build(BuildContext context) {
    return TextField(
      obscureText: obscurePassword,
      decoration: InputDecoration(
        labelText: 'Password',
        prefixIcon: const Icon(Icons.lock),
        suffixIcon: IconButton(
          icon: Icon(
            obscurePassword
                ? Icons.visibility
                : Icons.visibility_off,
          ),
          onPressed: () {
            setState(() {
              obscurePassword = !obscurePassword;
            });
          },
        ),
        border: const OutlineInputBorder(),
      ),
    );
  }
}




21. Creating a Multiline Text Input Field


Use maxLines to allow the user to enter multiple lines of text.


TextField(
  maxLines: 5,
  decoration: const InputDecoration(
    labelText: 'Description',
    hintText: 'Write your description',
    border: OutlineInputBorder(),
  ),
)

Common Uses



  • Comments

  • Feedback

  • Address

  • Messages

  • Descriptions

  • Notes




22. Limiting Input Length


The maxLength property can limit the number of characters entered.


TextField(
  maxLength: 20,
  decoration: const InputDecoration(
    labelText: 'Username',
    border: OutlineInputBorder(),
  ),
)



23. Text Capitalization


The textCapitalization property controls automatic capitalization behavior.


TextField(
  textCapitalization: TextCapitalization.words,
  decoration: const InputDecoration(
    labelText: 'Full Name',
    border: OutlineInputBorder(),
  ),
)

Common options include:



  • TextCapitalization.none

  • TextCapitalization.characters

  • TextCapitalization.words

  • TextCapitalization.sentences




24. Text Alignment


TextField(
  textAlign: TextAlign.center,
  decoration: const InputDecoration(
    labelText: 'OTP',
    border: OutlineInputBorder(),
  ),
)

Common alignment values include TextAlign.start, TextAlign.center, and TextAlign.end.




25. Read-Only Text Input


Use readOnly: true when users should be able to view or select the content but should not edit it.


TextField(
  readOnly: true,
  controller: TextEditingController(
    text: 'User ID: 1001',
  ),
  decoration: const InputDecoration(
    labelText: 'User ID',
    border: OutlineInputBorder(),
  ),
)



26. Disabled Text Input Field


Set enabled: false when the field should not accept interaction.


TextField(
  enabled: false,
  decoration: const InputDecoration(
    labelText: 'Disabled Field',
    border: OutlineInputBorder(),
  ),
)



27. Autofocus


The autofocus property can request focus when the TextField first becomes visible. This can be useful for search screens and similar interfaces. :contentReference[oaicite:7]{index=7}


TextField(
  autofocus: true,
  decoration: const InputDecoration(
    labelText: 'Search',
    border: OutlineInputBorder(),
  ),
)



28. FocusNode


A FocusNode can be used when an application needs programmatic control over which text field has keyboard focus. Focus nodes are long-lived objects and should have their lifecycle managed appropriately. :contentReference[oaicite:8]{index=8}


class FocusExample extends StatefulWidget {
  const FocusExample({super.key});

  @override
  State createState() => _FocusExampleState();
}

class _FocusExampleState extends State {
  final nameFocus = FocusNode();

  @override
  void dispose() {
    nameFocus.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return TextField(
      focusNode: nameFocus,
      decoration: const InputDecoration(
        labelText: 'Name',
        border: OutlineInputBorder(),
      ),
    );
  }
}




29. Moving Focus Between Fields


Focus can be moved from one TextField to another, which is useful for login and registration forms.


class LoginFields extends StatefulWidget {
  const LoginFields({super.key});

  @override
  State createState() => _LoginFieldsState();
}

class _LoginFieldsState extends State {
  final emailFocus = FocusNode();
  final passwordFocus = FocusNode();

  @override
  void dispose() {
    emailFocus.dispose();
    passwordFocus.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        TextField(
          focusNode: emailFocus,
          textInputAction: TextInputAction.next,
          onSubmitted: (_) {
            FocusScope.of(context).requestFocus(passwordFocus);
          },
          decoration: const InputDecoration(
            labelText: 'Email',
            border: OutlineInputBorder(),
          ),
        ),
        const SizedBox(height: 16),
        TextField(
          focusNode: passwordFocus,
          obscureText: true,
          decoration: const InputDecoration(
            labelText: 'Password',
            border: OutlineInputBorder(),
          ),
        ),
      ],
    );
  }
}




30. Hiding the Keyboard


Keyboard focus can be removed using FocusScope.of(context).unfocus().


ElevatedButton(
  onPressed: () {
    FocusScope.of(context).unfocus();
  },
  child: const Text('Hide Keyboard'),
)



31. Input Formatters


Input formatters can be used to restrict or transform user input. They are useful when an input must follow a specific format.


Import the Flutter services package:


import 'package:flutter/services.dart';

Digits Only


TextField(
  keyboardType: TextInputType.number,
  inputFormatters: [
    FilteringTextInputFormatter.digitsOnly,
  ],
  decoration: const InputDecoration(
    labelText: 'Enter Number',
    border: OutlineInputBorder(),
  ),
)

Maximum Input Length


TextField(
  inputFormatters: [
    LengthLimitingTextInputFormatter(10),
  ],
  decoration: const InputDecoration(
    labelText: 'Input',
    border: OutlineInputBorder(),
  ),
)



32. TextInputAction


textInputAction controls the action button displayed by the software keyboard.


TextField(
  textInputAction: TextInputAction.next,
  decoration: const InputDecoration(
    labelText: 'Name',
    border: OutlineInputBorder(),
  ),
)

Other commonly used values include:



  • TextInputAction.next

  • TextInputAction.done

  • TextInputAction.search

  • TextInputAction.go

  • TextInputAction.send




33. Styling Focused and Enabled Borders


TextField(
  decoration: InputDecoration(
    labelText: 'Email',
    border: const OutlineInputBorder(),
    enabledBorder: OutlineInputBorder(
      borderSide: BorderSide(
        color: Colors.grey,
      ),
    ),
    focusedBorder: OutlineInputBorder(
      borderSide: BorderSide(
        color: Colors.blue,
        width: 2,
      ),
    ),
  ),
)



34. Helper Text


Helper text can provide additional instructions to the user.


TextField(
  decoration: const InputDecoration(
    labelText: 'Username',
    helperText: 'Use 5 to 20 characters',
    border: OutlineInputBorder(),
  ),
)



35. Error Text


errorText can be used to display an input error message.


TextField(
  decoration: const InputDecoration(
    labelText: 'Email',
    errorText: 'Please enter a valid email',
    border: OutlineInputBorder(),
  ),
)



36. TextField and TextFormField


Flutter provides both TextField and TextFormField. A TextField is commonly used for standalone text input, while TextFormField wraps a TextField and integrates it with a surrounding Form, providing features such as validation. :contentReference[oaicite:9]{index=9}












FeatureTextFieldTextFormField
Basic text inputYesYes
InputDecorationYesYes
ControllerYesYes
Form integrationNo direct FormField integrationYes
ValidatorNot directly provided as a FormFieldYes
onChangedYesYes
Password inputYesYes
Multiline inputYesYes



37. Creating a Form with TextFormField


For forms that need validation, create a Form, provide a GlobalKey, and add TextFormField widgets with validator functions. Flutter's official form recipe follows this pattern. :contentReference[oaicite:10]{index=10}


class LoginForm extends StatefulWidget {
  const LoginForm({super.key});

  @override
  State createState() => _LoginFormState();
}

class _LoginFormState extends State {
  final formKey = GlobalKey();

  @override
  Widget build(BuildContext context) {
    return Form(
      key: formKey,
      child: Column(
        children: [
          TextFormField(
            decoration: const InputDecoration(
              labelText: 'Email',
              border: OutlineInputBorder(),
            ),
            validator: (value) {
              if (value == null || value.isEmpty) {
                return 'Please enter your email';
              }
              return null;
            },
          ),
          const SizedBox(height: 16),
          ElevatedButton(
            onPressed: () {
              if (formKey.currentState!.validate()) {
                print('Form is valid');
              }
            },
            child: const Text('Submit'),
          ),
        ],
      ),
    );
  }
}




38. Complete Registration Text Input Example


import 'package:flutter/material.dart';

class RegistrationPage extends StatefulWidget {
  const RegistrationPage({super.key});

  @override
  State createState() => _RegistrationPageState();
}

class _RegistrationPageState extends State {
  final nameController = TextEditingController();
  final emailController = TextEditingController();
  final phoneController = TextEditingController();
  final passwordController = TextEditingController();

  @override
  void dispose() {
    nameController.dispose();
    emailController.dispose();
    phoneController.dispose();
    passwordController.dispose();
    super.dispose();
  }

  void register() {
    final name = nameController.text.trim();
    final email = emailController.text.trim();
    final phone = phoneController.text.trim();
    final password = passwordController.text;

    if (name.isEmpty ||
        email.isEmpty ||
        phone.isEmpty ||
        password.isEmpty) {
      ScaffoldMessenger.of(context).showSnackBar(
        const SnackBar(
          content: Text('Please fill all fields'),
        ),
      );
      return;
    }

    ScaffoldMessenger.of(context).showSnackBar(
      const SnackBar(
        content: Text('Registration successful'),
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Registration'),
      ),
      body: SingleChildScrollView(
        padding: const EdgeInsets.all(20),
        child: Column(
          children: [
            TextField(
              controller: nameController,
              textCapitalization: TextCapitalization.words,
              decoration: const InputDecoration(
                labelText: 'Full Name',
                prefixIcon: Icon(Icons.person),
                border: OutlineInputBorder(),
              ),
            ),
            const SizedBox(height: 16),
            TextField(
              controller: emailController,
              keyboardType: TextInputType.emailAddress,
              decoration: const InputDecoration(
                labelText: 'Email Address',
                prefixIcon: Icon(Icons.email),
                border: OutlineInputBorder(),
              ),
            ),
            const SizedBox(height: 16),
            TextField(
              controller: phoneController,
              keyboardType: TextInputType.phone,
              decoration: const InputDecoration(
                labelText: 'Phone Number',
                prefixIcon: Icon(Icons.phone),
                border: OutlineInputBorder(),
              ),
            ),
            const SizedBox(height: 16),
            TextField(
              controller: passwordController,
              obscureText: true,
              decoration: const InputDecoration(
                labelText: 'Password',
                prefixIcon: Icon(Icons.lock),
                border: OutlineInputBorder(),
              ),
            ),
            const SizedBox(height: 24),
            SizedBox(
              width: double.infinity,
              child: ElevatedButton(
                onPressed: register,
                child: const Text('Register'),
              ),
            ),
          ],
        ),
      ),
    );
  }
}




39. Creating a Search Input Field


TextField(
  textInputAction: TextInputAction.search,
  onSubmitted: (value) {
    print('Search: $value');
  },
  decoration: const InputDecoration(
    hintText: 'Search products...',
    prefixIcon: Icon(Icons.search),
    border: OutlineInputBorder(),
  ),
)

Search fields can also use onChanged to update results while the user types. Flutter's documentation specifically describes this pattern for search and autocomplete experiences. :contentReference[oaicite:11]{index=11}




40. Creating a Chat Message Input


class MessageInput extends StatefulWidget {
  const MessageInput({super.key});

  @override
  State createState() => _MessageInputState();
}

class _MessageInputState extends State {
  final messageController = TextEditingController();

  @override
  void dispose() {
    messageController.dispose();
    super.dispose();
  }

  void sendMessage() {
    final message = messageController.text.trim();

    if (message.isEmpty) {
      return;
    }

    print('Message: $message');
    messageController.clear();
  }

  @override
  Widget build(BuildContext context) {
    return Row(
      children: [
        Expanded(
          child: TextField(
            controller: messageController,
            textInputAction: TextInputAction.send,
            decoration: const InputDecoration(
              hintText: 'Type a message...',
              border: OutlineInputBorder(),
            ),
            onSubmitted: (_) {
              sendMessage();
            },
          ),
        ),
        IconButton(
          onPressed: sendMessage,
          icon: const Icon(Icons.send),
        ),
      ],
    );
  }
}




41. Important TextField Properties





















PropertyDescription
controllerControls and retrieves the entered text.
decorationCustomizes labels, hints, borders, icons, and errors.
keyboardTypeSpecifies the expected keyboard/input type.
textInputActionControls the keyboard action button.
obscureTextHides entered characters.
maxLinesControls the maximum number of lines.
minLinesControls the minimum number of lines.
maxLengthLimits the number of characters.
onChangedRuns whenever the text changes.
onSubmittedRuns when the user submits the field.
focusNodeControls and monitors focus.
autofocusRequests focus when the field appears.
readOnlyPrevents editing while keeping the field interactive.
enabledEnables or disables the input field.
inputFormattersRestricts or transforms input.
textCapitalizationControls automatic text capitalization.
textAlignControls horizontal text alignment.



42. Best Practices for Creating Text Input Fields



  • Use a meaningful label for every important input field.

  • Use hint text when an example will help the user.

  • Choose an appropriate keyboard type such as email, phone, or number.

  • Use TextEditingController when you need to read or modify input programmatically.

  • Dispose controllers when they are no longer needed. :contentReference[oaicite:12]{index=12}

  • Use obscureText for password input.

  • Use TextFormField and Form when input validation is required.

  • Use appropriate input formatters for restricted input.

  • Use multiline fields for descriptions and comments.

  • Use FocusNode when the form requires custom focus management.

  • Make text fields sufficiently large and clear for comfortable interaction.

  • Use meaningful error messages instead of generic messages such as "Invalid input".




43. Common Mistakes


Mistake 1: Creating Controllers Inside build()


Avoid repeatedly creating controllers inside the build() method.


Mistake 2: Not Disposing Controllers


@override
void dispose() {
  nameController.dispose();
  super.dispose();
}

Mistake 3: Using the Wrong Keyboard Type


For example, an email field should normally use:


keyboardType: TextInputType.emailAddress

Mistake 4: Forgetting Password Obscuring


TextField(
  obscureText: true,
)

Mistake 5: Not Handling Keyboard Overflow


Forms containing many input fields may need a scrolling parent such as SingleChildScrollView so that fields remain accessible when the keyboard appears.




44. Practical Exercise


Create a Flutter registration screen containing the following text input fields:



  1. Full Name

  2. Email Address

  3. Phone Number

  4. Password

  5. Confirm Password

  6. Address

  7. Short Bio


Requirements:



  • Use appropriate labels and hint text.

  • Add prefix icons.

  • Use TextEditingController.

  • Use appropriate keyboard types.

  • Hide password characters.

  • Use multiline input for Address and Bio.

  • Limit the Bio to a suitable number of characters.

  • Add a Register button.

  • Display a success message after submission.




45. Interview Questions



  1. What is TextField in Flutter?

  2. How do you create a basic text input field?

  3. What is InputDecoration?

  4. What is the difference between hintText and labelText?

  5. What is TextEditingController?

  6. Why should TextEditingController be disposed?

  7. How do you retrieve text from a TextField?

  8. What is the purpose of onChanged?

  9. What is the difference between onChanged and onSubmitted?

  10. How do you create a password field?

  11. How do you create a multiline text input?

  12. How can you limit the number of characters?

  13. What is keyboardType?

  14. What is FocusNode?

  15. How can you move focus between two TextFields?

  16. What is TextFormField?

  17. What is the difference between TextField and TextFormField?

  18. How can you validate text input in Flutter?

  19. How can inputFormatters be used?

  20. How can you customize a TextField border?




46. Quick Revision


















ConceptExample
Basic inputTextField()
LabellabelText: 'Name'
HinthintText: 'Enter name'
Controllercontroller: nameController
Read valuecontroller.text
Email inputTextInputType.emailAddress
Phone inputTextInputType.phone
PasswordobscureText: true
MultilinemaxLines: 5
Character limitmaxLength: 20
Input changesonChanged
SubmitonSubmitted
FocusFocusNode
Form validationTextFormField



47. Key Takeaways



  • TextField is the primary Flutter widget for creating text input fields.

  • InputDecoration controls the appearance of the field.

  • TextEditingController provides programmatic access to entered text.

  • onChanged is useful for responding to input changes.

  • onSubmitted is useful for handling keyboard submission.

  • keyboardType helps provide an appropriate input keyboard.

  • obscureText is commonly used for passwords.

  • maxLines allows multiline text input.

  • inputFormatters can restrict or transform input.

  • FocusNode provides programmatic focus control.

  • TextFormField is useful for forms that require validation. :contentReference[oaicite:13]{index=13}




48. Official Flutter Resources





49. JustAcademy Flutter Resources



whatsapp